package dw.fastfile.common.enums;


import dw.fastfile.common.annotations.Dict;
import dw.fastfile.common.constants.RedisConstants;
import dw.fastfile.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @description: 枚举字段处理
 * @author: wanghao
 * @create: 2022-10-12 16:20
 **/
@Slf4j
@Service
public class EnumFieldService {
    private static Map<String, Map<String, Object>> allEnum = new HashMap<>();

    @Resource
    private JdbcTemplate jdbcTemplate;

    private static String SQL = "select enumtype , enumcode, enumname \n" +
            "from iuap_metadata_service.aa_enum_type type\n" +
            "         left join iuap_metadata_service.aa_enum_item item on type.id = item.typeid\n" +
            "where type.ideleted = 0\n" +
            "  and item.ideleted = 0";

    public Map<String, Object> getEnum(String enumType) {
        if (StringUtils.isAnyBlank(RedisConstants.REDIS_KEY_ENUM, enumType)) {
            throw new BusinessException("查枚举值参数不能为空");
        }

        this.init();

        return allEnum.get(enumType);
    }

    /**
     * 根据枚举code查name
     *
     * @param enumType 枚举所属类型
     * @param code     枚举值code
     * @return 枚举name
     */
    public Object getName(String enumType, String code) {
        if (StringUtils.isAnyBlank(RedisConstants.REDIS_KEY_ENUM, enumType, code)) {
            throw new BusinessException("查枚举值参数不能为空");
        }

        this.init();

        Map<String, Object> codeMap = allEnum.get(enumType);
        if (codeMap == null) {
            throw new RuntimeException("查枚举值报错，枚举不存在：" + enumType);
        }

        return codeMap.get(code);
    }


    public void putEnum() {
        // 查数据库
        List<Map<String, Object>> list = jdbcTemplate.queryForList(SQL);
        if (list.isEmpty()) {
            return;
        }

        // 根据枚举分组
        for (Map<String, Object> m : list) {
            String enumCode = m.get("enumtype") + "";

            Map<String, Object> codeMap = allEnum.get(enumCode);
            if (null == codeMap) {
                codeMap = new HashMap<>();
            }
            codeMap.put(m.get("enumcode") + "", m.get("enumname") + "");

            allEnum.put(enumCode, codeMap);
        }

    }

    private void init() {
        if (allEnum.isEmpty()) {
            this.putEnum();
        }

        if (allEnum.isEmpty()) {
            throw new RuntimeException("缓存中不存在枚举，请检查");
        }
    }

    public void processDict(Object obj) {
        Class<?> clazz = obj.getClass();

        // 遍历所有字段
        for (Field field : clazz.getDeclaredFields()) {
            Object fieldValueCode = null;
            try {
                // 设置字段可访问
                field.setAccessible(true);
                fieldValueCode = field.get(obj);
                // 递归处理引用类型字段
                if (!isPrimitiveOrWrapper(field.getType())) {
                    if (fieldValueCode instanceof List) { // 处理列表对象
                        List<?> list = (List<?>) fieldValueCode;
                        for (Object listItem : list) {
                            this.processDict(listItem);
                        }
                    } else if (fieldValueCode instanceof Set) { // 处理Set集合对象
                        Set<?> set = (Set<?>) fieldValueCode;
                        for (Object setItem : set) {
                            this.processDict(setItem);
                        }
                    } else if (fieldValueCode instanceof Map) { // 处理Map对象
                        Map<?, ?> map = (Map<?, ?>) fieldValueCode;
                        for (Map.Entry<?, ?> entry : map.entrySet()) {
                            this.processDict(entry.getValue());
                        }
                    } else { // 处理单个引用类型字段
                        this.processDict(fieldValueCode);
                    }
                }
            } catch (Exception e) {
                log.error("处理字典注解code转name异常" + e.getMessage());
            }


            // 判断字段上是否存在指定的注解
            if (field.isAnnotationPresent(Dict.class)) {
                Annotation annotation = field.getAnnotation(Dict.class);
                Dict dict = (Dict) annotation;

                // 获取注解上的属性值
                String eType = dict.dictType();

                try {

                    if (fieldValueCode == null) {
                        continue;
                    }
                    String name = this.getName(eType, fieldValueCode + "") + "";

                    String formatVal = this.getFormatVal(dict.exportFormat(), fieldValueCode + "", name);

                    // 根据需要进行字段的赋值处理
                    field.set(obj, formatVal);


                } catch (Exception e) {
                    log.error("处理字典注解code转name异常" + e.getMessage());
                }

            }
        }
    }

    /**
     * 判断是否为基本类型或包装类型
     *
     * @param clazz
     * @return
     */
    private static boolean isPrimitiveOrWrapper(Class<?> clazz) {
        return clazz.isPrimitive() || clazz.equals(Boolean.class)
                || clazz.equals(Byte.class) || clazz.equals(Character.class)
                || clazz.equals(Short.class) || clazz.equals(Integer.class)
                || clazz.equals(Long.class) || clazz.equals(Float.class)
                || clazz.equals(Double.class) || clazz.equals(String.class);
    }

    private String getFormatVal(ExportFormatEnum exportFormatEnum, String code, String name) {
        String format = exportFormatEnum.getType();
        if (ExportFormatEnum.name.getType().equals(format)) {
            return name;
        }
        if (ExportFormatEnum.code_name.getType().equals(format)) {
            return code + ":" + name;
        }
        if (ExportFormatEnum.code_name2.getType().equals(format)) {
            return code + "_" + name;
        }
        if (ExportFormatEnum.code_name3.getType().equals(format)) {
            return code + " " + name;
        }
        return "";
    }


}
